package com.ywl5320.mymusic.render;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.util.Log;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import static android.content.ContentValues.TAG;

/**
 * Created by Chen qin lang on 2018/7/14.
 * 邮箱 :   619766577@qq.com
 */
public class WlRender implements GLSurfaceView.Renderer {
    public float[] vertex = {
            -1.0f, -1.0f,
            1.0f, -1.0f,
            -1.0f, 1.0f,
            1.0f, 1.0f,
    };
    public float[] fragment = {
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f,
    };
    /*
    * "attribute vec4 vPosition ; " +
            "void main() {" +
            "  gl_Position = vPosition ;" +
            "}";*/
    public String vertexShader = "attribute vec4 av_position ;" +
            "attribute vec2 af_Position ;" +
            "varying vec2 v_texPo ;" +
            "void main(){" +
            "   v_texPo = af_Position ;" +
            "   gl_Position = av_position ;" +
            "}";
/*
* "precision mediump float ; " +
         "uniform vec4 vColor ;" +
         "void main() {" +
         "  gl_FragColor = vColor ; " +
         "}*/
    public String texture_shader = "precision mediump float;" +
            "varying vec2 v_texPo ;" +
            "uniform sampler2D sample_y;" +
            "uniform sampler2D sample_u;" +
            "uniform sampler2D sample_v;" +
            "void main(){" +
            "   float y,u,v ;" +
            "   y = texture2D(sample_y, v_texPo).r ;" +
            "   u = texture2D(sample_u, v_texPo).r - 0.5;" +
            "   v = texture2D(sample_v, v_texPo).r - 0.5 ;" +
            "   vec3 rgb;" +
            "   rgb.r = y + 1.403 * v ;" +
            "   rgb.g = y - 0.344 * u- 0.714 * v ;" +
            "   rgb.b = y + 1.770 * u ;" +
            "   gl_FragColor = vec4(rgb,1) ;" +
            "} ";
    private FloatBuffer floatBuffer;
    private int program;
    private int af_position;
    private int av_position;
    private int v_texture;
    private FloatBuffer fragment_Buffer;
    private int u_texture;
    private int y_texture;
    private int width;
    private int height;
    private ByteBuffer yuv_y;
    private ByteBuffer yuv_u;
    private ByteBuffer yuv_v;
    private int[] textures = new int[3];


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertex.length * 4);
        byteBuffer.order(ByteOrder.nativeOrder());
        floatBuffer = byteBuffer.asFloatBuffer().put(vertex);
        floatBuffer.position(0);
//        floatBuffer.(vertex);

/*        fragment_Buffer = ByteBuffer.allocateDirect(fragment.length * 4).
                order(ByteOrder.nativeOrder()).
                asFloatBuffer()
                .put(fragment).position(0);*/

        ByteBuffer fragmentBuffer = ByteBuffer.allocateDirect(fragment.length * 4);
        fragmentBuffer.order(ByteOrder.nativeOrder());
        fragment_Buffer = fragmentBuffer.asFloatBuffer().put(fragment);
        fragment_Buffer.position(0);


        int vertex_shader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        GLES20.glShaderSource(vertex_shader, vertexShader);
        GLES20.glCompileShader(vertex_shader);
        int[] shader_Name = new int[1];
        GLES20.glGetShaderiv(vertex_shader, GLES20.GL_COMPILE_STATUS, shader_Name, 0);
        if (shader_Name[0] == 0) {
            GLES20.glDeleteShader(vertex_shader);
        }
        int fragment = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        GLES20.glShaderSource(fragment, texture_shader);
        GLES20.glCompileShader(fragment);
        int[] framgnet_status = new int[1];
        GLES20.glGetShaderiv(fragment, GLES20.GL_COMPILE_STATUS, framgnet_status, 0);
        if (framgnet_status[0] == 0) {
            GLES20.glDeleteShader(fragment);
            Log.e(TAG, "onSurfaceCreated: " + GLES20.glGetShaderInfoLog(fragment));
        }


        program = GLES20.glCreateProgram();
        GLES20.glAttachShader(program, vertex_shader);
        GLES20.glAttachShader(program, fragment);
        GLES20.glLinkProgram(program);
        int[] program_stau = new int[1];
        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, program_stau, 0);
        if (program_stau[0] !=GLES20.GL_TRUE) {
            GLES20.glDeleteProgram(program);
            Log.e(TAG, "onSurfaceCreated:" + GLES20.glGetProgramInfoLog(program));
            return;
        }
        af_position = GLES20.glGetAttribLocation(program, "af_Position");
        av_position = GLES20.glGetAttribLocation(program, "av_position");
        //v_texture = GLES20.glGetAttribLocation(program, "v_texture");
        y_texture = GLES20.glGetUniformLocation(program, "sample_y");
        u_texture = GLES20.glGetUniformLocation(program, "sample_u");
        v_texture = GLES20.glGetUniformLocation(program, "sample_v");

        GLES20.glGenTextures(3, textures, 0);
        for (int i = 0; i < 3; i++) {

            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        }
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT );
        GLES20.glClearColor(0.0f,0.0f,0.0f,1.0f);
        renderYUV();
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);


    }

    private void renderYUV() {
        if (width > 0 && height > 0 && yuv_y != null && yuv_u != null && yuv_v != null) {
            Log.e(TAG, "renderYUV: " );

            GLES20.glUseProgram(program);
            GLES20.glEnableVertexAttribArray(av_position);
            GLES20.glVertexAttribPointer(av_position, 2, GLES20.GL_FLOAT, false, 0, floatBuffer);

            GLES20.glEnableVertexAttribArray(af_position);
            GLES20.glVertexAttribPointer(af_position, 2, GLES20.GL_FLOAT, false, 0, fragment_Buffer);

            GLES20.glActiveTexture(textures[0]);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width, height, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yuv_y);

            GLES20.glActiveTexture(textures[1]);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[1]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width / 2, height / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yuv_u);

            GLES20.glActiveTexture(textures[2]);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[2]);
            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, width / 2, height / 2, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yuv_v);

            GLES20.glUniform1i(y_texture, 0);
            GLES20.glUniform1i(u_texture, 1);
            GLES20.glUniform1i(v_texture, 2);
            yuv_y.clear();
            yuv_u.clear();
            yuv_v.clear();

            yuv_y=null;
            yuv_u=null;
            yuv_v=null;

        }
    }

    public void onRenderYUV(int width, int height, byte[] y, byte[] u, byte[] v) {

        this.width = width;
        this.height = height;
        this.yuv_y = ByteBuffer.wrap(y);
        this.yuv_u = ByteBuffer.wrap(u);
        this.yuv_v = ByteBuffer.wrap(v);

    }
}
